package cn.tedu.lucky.draw.server.aspect;

import cn.tedu.lucky.draw.server.common.annotation.OperationLog;
import cn.tedu.lucky.draw.server.protocol.po.UserLog;
import cn.tedu.lucky.draw.server.repository.UserLogRepository;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Aspect
@Component
public class LogAspect {

    @Autowired
    private UserLogRepository userLogRepository;

    @Pointcut("@annotation(cn.tedu.lucky.draw.server.common.annotation.OperationLog)")
    public void doLog(){

    }

    @Around("doLog()")
    public Object doLogAround(ProceedingJoinPoint joinPoint) throws Throwable{
        //初始状态,默认是成功的
        int status=1;
        //错误信息
        String error=null;
        //耗时
        long time=0l;
        //开始执行日志处理
        long t1 = System.currentTimeMillis();
        try{
            Object proceed = joinPoint.proceed();
            long t2 = System.currentTimeMillis();
            time =t2-t1;
            return proceed;
        }catch (Throwable e){
            long t3 = System.currentTimeMillis();
            time =t3-t1;
            status=0;
            error=e.getMessage();
            throw e;
        }finally {
            saveOperationLog(joinPoint,status,error,time);
        }
    }

    private void saveOperationLog(ProceedingJoinPoint joinPoint, int status, String error, long time) throws NoSuchMethodException, JsonProcessingException {

        //获取IP地址，需要先获取请求对象
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest httpServletRequest = requestAttributes.getRequest();
        String ip = httpServletRequest.getRemoteAddr();
        //用户名
        String username = "tedu";
        //获取操作名
        Class<?> targetCls = joinPoint.getTarget().getClass();
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = targetCls.getDeclaredMethod(
                methodSignature.getName(),
                methodSignature.getParameterTypes()
        );
        OperationLog operationLog = method.getAnnotation(OperationLog.class);
        String operation = operationLog.operation();
        //通过类路径和方法名称去形成当前所记录的方法名称
        String methodName =targetCls.getName()+"."+method.getName();
        //获取方法参数
        ObjectMapper mapper=new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());
        String params=mapper.writeValueAsString(joinPoint.getArgs());

        //封装用户日志对象
        UserLog userLog = new UserLog();
        userLog.setIp(ip);
        userLog.setUsername(username);
        userLog.setCreateTime(LocalDateTime.now());
        userLog.setOperation(operation);
        userLog.setMethod(methodName);
        userLog.setParams(params);
        userLog.setStatus(status);
        userLog.setError(error);
        userLog.setTime(time);
        userLogRepository.save(userLog);
    }
}
